﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PBO.Network.Proxy
{
    public class FourPlayerAgent
    {
        #region Varibles
        private FourPlayerAgentServer _server;

        private Dictionary<int, byte> _players = new Dictionary<int, byte>();
        private Dictionary<byte, string> _positions = new Dictionary<byte, string>();
        private object _locker = new object();
        #endregion

        public FourPlayerAgent(int identity, FourPlayerAgentServer server, string hostName)
        {
            this.AgentID = identity;
            _server = server;
            _positions[1] = hostName;
            for (byte i = 2; i < 5; i++)
            {
                _positions[i] = "";
            }
        }

        internal void PlayerLogon(int identity)
        {
            _players[identity] = 0;
            Dictionary<byte, string> pos = Positions;
            foreach (byte key in pos.Keys)
            {
                _server.SetPosition(identity, key, pos[key]);
            }
        }

        internal void SetPosition(int identity, byte position, string player)
        {
            lock (_locker)
            {
                if (_positions[position] == "")
                {
                    SetPosition(position, player);
                    if (_players[identity] != 0)
                    {
                        SetPosition(_players[identity], "");
                    }
                    else
                    {
                        _server.UpdateRoom(this.AgentID, GetPlayerCount());
                    }
                    _players[identity] = position;
                    _server.SetPositionSuccess(identity, position);
                }
            }
        }

        internal void SetPosition(byte position, string player)
        {
            _positions[position] = player;
            Parallel.ForEach(PlayerList, p => _server.SetPosition(p, position, player));
        }

        internal void StartBattle(int battleIdentity)
        {
            Parallel.ForEach(PlayerList, p => _server.StartBattle(p, battleIdentity));
            this.Closed = true;
        }

        internal void PlayerExit(int identity)
        {
            if (_players[identity] != 0)
            {
                SetPosition(_players[identity], "");
                _players.Remove(identity);
                _server.UpdateRoom(this.AgentID, GetPlayerCount());
            }
        }

        internal void Close()
        {
            this.Closed = true;
            Parallel.ForEach(PlayerList, p => _server.Close(p));
        }

        public byte GetPlayerCount()
        {
            return (byte)(4 - Positions.Values.Count(s => string.IsNullOrEmpty(s)));
        }

        public int AgentID { get; private set; }

        public string HostName
        {
            get { return _positions[1]; }
        }

        private IEnumerable<int> PlayerList
        {
            get { return _players.Keys.ToArray(); }
        }

        private Dictionary<byte, string> Positions
        {
            get
            {
                return new Dictionary<byte, string>(_positions);
            }
        }

        public bool Closed { get; private set; }
    }
}
